package org.mnswf.scorchedearth.board {
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.GradientType;
	import flash.display.Sprite;
	import flash.display.SpreadMethod;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;	
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import mx.core.UIComponent;

	public class ScorchedEarth extends UIComponent
	{
		private static const GAME_WIDTH:int = 800;
		private static const GAME_HEIGHT:int = 500;
		private static const EXPLOSION_WIDTH:int = 256;
		private static const EXPLOSION_HEIGHT:int = 256;
		private static const EARTH_COLOR:Number = 0xAA333300;
		private static const MAX_EXPLOSIONS:int = 10;
		private static const SCORCH_RADIUS:Number = 20.0;
		private var earthData:BitmapData;
		private var earth:Bitmap;
		private var earthY:Array = new Array(GAME_WIDTH);
		private var connection:NetConnection;
		private var client:Array = new Array(MAX_EXPLOSIONS);
		private var explosionVideo:Array = new Array(MAX_EXPLOSIONS);
		private var explosionVideoStream:Array = new Array(MAX_EXPLOSIONS);
		private var nextVideoIndex:int = 0;

		public function ScorchedEarth()
		{
			stage.align = StageAlign.TOP_LEFT;	
			stage.scaleMode = StageScaleMode.NO_SCALE;
			drawSky();
			drawEarth();
			connection = new NetConnection();
			connection.connect(null);
			for (var i:int=0; i<MAX_EXPLOSIONS; i++) {
				explosionVideo[i] = new Video(EXPLOSION_WIDTH, EXPLOSION_HEIGHT);
				explosionVideoStream[i] = new NetStream(connection);
				client[i] = new Object();
				explosionVideoStream[i].client = client[i];
				explosionVideo[i].attachNetStream(explosionVideoStream[i]);
				addChild(explosionVideo[i]);				
			}
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		
		private function drawSky():void {
			//add a radiant gradiant
			var fillType:String = GradientType.LINEAR;
			var colors:Array = [0xFF0000, 0x0000FF];
			var alphas:Array = [1, 1];
			var ratios:Array = [0x00, 0xFF];
			var matr:Matrix = new Matrix();
			matr.createGradientBox(GAME_WIDTH, GAME_HEIGHT, Math.PI / 2, 0, 0);
			var spreadMethod:String = SpreadMethod.PAD;
			this.graphics.beginGradientFill(fillType, colors, alphas, ratios, matr, spreadMethod);  
			this.graphics.drawRect(0, 0, GAME_WIDTH, GAME_HEIGHT);			
		}

		private function drawEarth():void {
			//start with a flat surface			
			for (var i:int = 0; i < GAME_WIDTH; i++) {
				earthY[i] = GAME_HEIGHT / 2;
			}
			//now fractalize the surface
			fractalizeEarth(0, GAME_WIDTH - 1);
			//populate the bitmap data with the values
			repaintEarthData();
		}
		
		private function repaintEarthData():void {
			earthData = new BitmapData(GAME_WIDTH, GAME_HEIGHT, true, 0x00000000);
			for (var i:int = 0; i < GAME_WIDTH; i++) {
				earthData.fillRect(new Rectangle(i, earthY[i], 1, GAME_HEIGHT - 1), EARTH_COLOR);
			}			
			//create the bitmap with the bitmap data
			earth = new Bitmap(earthData);
			//render the earth to the screen			
			addChildAt(earth,0);			
		}
		
		private function fractalizeEarth(leftX:int, rightX:int):void {
			if ((rightX - leftX) > 1) {
				var middleX:int = (leftX + rightX) / 2;
				var offset:int = Math.random() * ((rightX - leftX) / 2);
				offset -= (rightX - leftX) / 4;
				earthY[middleX] = (earthY[leftX] + earthY[rightX]) / 2 + offset;
				fractalizeEarth(leftX, middleX);
				fractalizeEarth(middleX, rightX);
			}
		}		
		
		private function scorchEarth(x:int):void {
			displayExplosion(x);
			var leftEdge:int = x - SCORCH_RADIUS;
			if (leftEdge < 0) {
				leftEdge = 0;
			}
			var rightEdge:int = x + SCORCH_RADIUS;
			if (rightEdge >= GAME_WIDTH) {
				rightEdge = GAME_WIDTH - 1;
			}
			//carve out a semi-circle shape for a crater
			for (var i:int = leftEdge; i <= rightEdge; i++) {
				var angle:Number = (Number(i-x)/SCORCH_RADIUS)*Math.PI/2.0;
				var depth:Number = Math.cos(angle)*SCORCH_RADIUS;
				earthY[i] += depth;
				if (earthY[i] >= GAME_HEIGHT) {
					earthY[i] = GAME_HEIGHT-1;
				}
			}
			removeChild(earth);
			repaintEarthData();
		}
		
		private function displayExplosion(x:int):void {
			var explosion:Video = explosionVideo[nextVideoIndex];
			explosion.clear()
			explosion.x = x - EXPLOSION_WIDTH / 2;
			explosion.y = earthY[x] - EXPLOSION_HEIGHT / 2;
			var videoStream:NetStream = explosionVideoStream[nextVideoIndex];
			videoStream.close();
			videoStream.play("explode.flv");
			nextVideoIndex++;
			if (nextVideoIndex >= MAX_EXPLOSIONS) {
				nextVideoIndex = 0;
			}
		}
	
		private function onEnterFrame(event:Event):void {
			if (Math.random() < 0.1) {
				scorchEarth(Math.random() * GAME_WIDTH);
			}
		}
	}
}
